/*
 * Copyright (c) Ulrich Hilger, http://dev.uhilger.de, all rights reserved.
 *
 * Published under the terms and conditions of the Apache License 2.0,
 * see http://www.apache.org/licenses/LICENSE-2.0
 */

package de.uhilger.servicehub.view;

import de.uhilger.app.ui.GridBagHelper;
import de.uhilger.servicehub.ServiceHub;
import de.uhilger.servicehub.ctrl.action.AbstractServiceHubAction;
import de.uhilger.servicehub.ctrl.action.ActionResultListener;
import de.uhilger.servicehub.model.ServletContainer;
import de.uhilger.servicehub.server.AppServer;
import de.uhilger.servicehub.server.AppServer.ServerPart;
import de.uhilger.servicehub.server.ServerStatusListener;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.prefs.Preferences;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

/**
 * Panel of application ServiceHub that shows web applications currently present 
 * on a servlet container.
 *
 * @author Ulrich Hilger, <a href="http://dev.uhilger.de" target="_blank">http://dev.uhilger.de</a>
 * @author Published under the terms and conditions of
 * the <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache License 2.0</a>
 */
public class AppPanel extends JPanel 
  implements ServerStatusListener, ActionResultListener, ActionListener, ListSelectionListener {

  /** Resource identifier */
  private static final String RN_APP_PANEL_DEPLOY_FILE_LABEL = "appPanelDeployFileLabel";
  /** Resource identifier */
  private static final String RN_APP_PANEL_DEPLOY_BUTTON_TEXT = "appPanelDeployButtonText";
  /** Resource identifier */
  private static final String RN_APP_PANEL_START_BUTTON_TEXT = "appPanelStartButtonText";
  /** Resource identifier */
  private static final String RN_APP_PANEL_STOP_BUTTON_TEXT = "appPanelStopButtonText";
  /** Resource identifier */
  private static final String RN_APP_PANEL_UNDEPLOY_BUTTON_TEXT = "appPanelUndeployButtonText";
  /** Resource identifier */
  public static final String AC_APP_PANEL_FILE_SEL_BTN = "appPanelFileSelBtn";

  private JList appList;
  private JScrollPane listScroller;
  private AppServer server;
  private static JTextField deployFile;
  private JButton fileSelBtn;
  private JButton deployBtn;
  private JButton startBtn;
  private JButton stopBtn;
  private JButton undeployBtn;

  /**
   * Create a new object of class AppPanel that shows deployed web applications
   * currently present on a servlet container.
   *
   * @param dirSelAction action to select a directory
   * @param res  where to take strings from
   */
  public AppPanel(AbstractServiceHubAction dirSelAction, ResourceBundle res) {
    super();
    //this.server = server;
    buildUi(dirSelAction, res);
  }

  /**
   * Set the server for this AppPanel
   * @param server  the server
   */
  public void setServer(AppServer server) {
    if(server != null) {
      server.removeServerStatusListener(this);
    }
    this.server = server;
    server.addServerStatusListener(this);
  }

  /**
   * Create the user interface of this component
   *
   * @param dirSelAction  the action to use for folder selections
   * @param res  where to take static string resources from
   */
  private void buildUi(AbstractServiceHubAction dirSelAction, ResourceBundle res) {
    dirSelAction.addActionResultListener(this);

    JPanel listPanel = new JPanel();
    listPanel.setLayout(new BorderLayout());
    appList = new JList();
    appList.addListSelectionListener(this);
    listScroller = new JScrollPane(appList);
    listPanel.add(listScroller, BorderLayout.CENTER);

    GridBagHelper gbh = new GridBagHelper();
    GridBagConstraints c = new GridBagConstraints();
    GridBagLayout g = new GridBagLayout();

    JPanel deployPanel = new JPanel();
    deployPanel.setLayout(g);

    deployBtn = new JButton(res.getString(RN_APP_PANEL_DEPLOY_BUTTON_TEXT));
    deployBtn.addActionListener(this);
    gbh.addGridBagComponent(deployPanel, deployBtn, g, c, 0, 0, GridBagConstraints.CENTER);

    JLabel label = new JLabel(res.getString(RN_APP_PANEL_DEPLOY_FILE_LABEL));
    gbh.addGridBagComponent(deployPanel, label, g, c, 1, 0, GridBagConstraints.EAST);

    Preferences prefs = Preferences.userNodeForPackage(getClass());
    deployFile = new JTextField(prefs.get(ServiceHub.PREF_LAST_DEPLOY_FILE, ""));
    deployFile.setEditable(false);
    //deployFile.setText(server.getWebPath());
    gbh.addGridBagComponent(deployPanel, deployFile, g, c, 2, 0, GridBagConstraints.WEST,
            1, 1, GridBagConstraints.HORIZONTAL, 1, 1);

    fileSelBtn = new JButton();
    //dirSelAction.addActionResultListener(this);
    fileSelBtn.setAction(dirSelAction);
    fileSelBtn.setActionCommand(AC_APP_PANEL_FILE_SEL_BTN);
    fileSelBtn.setText("..");
    gbh.addGridBagComponent(deployPanel, fileSelBtn, g, c, 3, 0, GridBagConstraints.CENTER);

    deployPanel.setBorder(new EmptyBorder(12, 0, 0, 0));

    JPanel northCenterPanel = new JPanel();
    northCenterPanel.setLayout(new GridLayout(3, 1));
    startBtn = new JButton(res.getString(RN_APP_PANEL_START_BUTTON_TEXT));
    startBtn.setEnabled(false);
    startBtn.addActionListener(this);
    northCenterPanel.add(startBtn);
    stopBtn = new JButton(res.getString(RN_APP_PANEL_STOP_BUTTON_TEXT));
    stopBtn.setEnabled(false);
    stopBtn.addActionListener(this);
    northCenterPanel.add(stopBtn);
    undeployBtn = new JButton(res.getString(RN_APP_PANEL_UNDEPLOY_BUTTON_TEXT));
    undeployBtn.setEnabled(false);
    undeployBtn.addActionListener(this);
    northCenterPanel.add(undeployBtn);

    JPanel appBtnPanel = new JPanel(new BorderLayout());
    appBtnPanel.add(northCenterPanel, BorderLayout.NORTH);

    setLayout(new BorderLayout());

    add(listPanel, BorderLayout.WEST);
    add(deployPanel, BorderLayout.SOUTH);
    add(appBtnPanel, BorderLayout.EAST);

    setBorder(new EmptyBorder(12, 12, 12, 12));
  }

  /**
   * Get path and name of the file currently selected for deployment
   * @return  path and name of file currently selected to be deployed
   */
  public static String getDeployFileName() {
    return deployFile.getText();
  }

  /**
   * Start a currently deployed web application
   */
  private void startApp(Object app) {
    String appPath = app.toString();
    appPath = appPath.substring(0, appPath.indexOf(" " + ServletContainer.STOPPED));
    ServiceHub.log("startApp " + appPath, getClass(), Level.FINEST);
    try {
      server.startApp(appPath);
    } catch (Exception ex) {
      ServiceHub.logStackTrace(ex, getClass());
    }
  }

  /**
   * Stop a currently deployed web application
   */
  private void stopApp(Object app) {
    // TODO stop app
    String appPath = app.toString();
    appPath = appPath.substring(0, appPath.indexOf(":"));
    ServiceHub.log("stopApp " + appPath, getClass(), Level.FINEST);
    try {
      server.stopApp(appPath);
    } catch (Exception ex) {
      ServiceHub.logStackTrace(ex, getClass());
    }
  }

  /**
   * Stop and remove a web application from the servlet container
   * @param app  path of context to undeploy
   */
  private void undeployApp(Object app) {
    String appPath = app.toString();
    appPath = appPath.substring(0, appPath.indexOf(":"));
    ServiceHub.log("undeployApp " + appPath, getClass(), Level.FINEST);
    try {
      server.undeploy(appPath);
    } catch (Exception ex) {
      ServiceHub.logStackTrace(ex, getClass());
    }
  }

  /**
   * Update the list of web applications that are currently
   * deployed on the servlet container
   */
  private void updateAppList() {
    ServiceHub.log("serverStatusChanged apps", getClass(), Level.FINEST);
    appList.removeListSelectionListener(this);
    appList = new JList(server.getApps());
    appList.addListSelectionListener(this);
    listScroller.getViewport().setView(appList);
    undeployBtn.setEnabled(false);
    startBtn.setEnabled(false);
    stopBtn.setEnabled(false);
  }

  /* ---------------- ServerStatusListener ------------------- */

  /**
   * Handle changes in status of a server
   *
   * @param server  the server whose status has changed
   * @param part  the part that has changed
   */
  public void serverStatusChanged(AppServer server, ServerPart part) {
      switch(part) {
        case BASE:
          //webAppDir.setText(server.getWebPath());
          break;
        case APPS:
            ServiceHub.log("serverStatusChanged apps", getClass(), Level.FINEST);
            updateAppList();
          break;
        /*case SREPATH:
          srePath.setText(server.getSrePath());
          break;*/
        case STATUS:
          if(server.isRunning()) {
            ServiceHub.log("serverStatusChanged to run", getClass(), Level.FINEST);
            updateAppList();
          } else {
          }
          break;
      }
  }

  /* ------------------------- ActionResultListener --------------------- */

  /**
   * Handle the result of an action
   *
   * @param event the event that delivers a result
   * @param result  the result that requires handling
   */
  public void resultPresent(ActionEvent event, Object result) {
    ServiceHub.log("action result " + event.getActionCommand() + ", result: " +
            result, getClass(), Level.FINEST);
    Object o = event.getSource();
    if (o != null) {
      if (o.equals(fileSelBtn)) {
        if (result instanceof File) {
          String path = ((File) result).getAbsolutePath();
          deployFile.setText(path);
        }
      }
    }
  }

  /* --------------------- ActionListener ------------------ */

  /**
   * Handle the initiation of an action
   * @param e  the event to handle
   */
  public void actionPerformed(ActionEvent e) {
    ServiceHub.log("actionPerformed " + e.getActionCommand(), getClass(), Level.FINEST);
    Object src = e.getSource();
    if(src != null) {
      if(src.equals(deployBtn)) {
        ServiceHub.log("actionPerformed deploy button pressed", getClass(), Level.FINEST);
        try {
          server.deploy(getDeployFileName());
          Preferences prefs = Preferences.userNodeForPackage(getClass());
          prefs.put(ServiceHub.PREF_LAST_DEPLOY_FILE, getDeployFileName());
        } catch (Exception ex) {
          ServiceHub.logStackTrace(ex, getClass());
        }
      } else if(src.equals(startBtn)) {
        startApp(appList.getSelectedValue());
      } else if(src.equals(stopBtn)) {
        stopApp(appList.getSelectedValue());
      } else if(src.equals(undeployBtn)) {
        undeployApp(appList.getSelectedValue());
      }
    }
  }

  /* ---------------------- ListSelectionEventListener --------------- */

  /**
   * Handle selection of an item inside a list
   *
   * @param e  the event to handle
   */
  public void valueChanged(ListSelectionEvent e) {
    Object src = e.getSource();
    if(src.equals(appList)) {
      Object selectedValue = appList.getSelectedValue();
      if(selectedValue != null) {
        boolean isStopped = selectedValue.toString().contains(ServletContainer.STOPPED);
        //stopBtn.setEnabled(true);
        undeployBtn.setEnabled(true);
        stopBtn.setEnabled(!isStopped);
        startBtn.setEnabled(isStopped);
      }
    }
  }
}
